package cn.enjoy.tool.juc;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池队列阻塞
 * 模拟线上问题，商户回调创建印章and网监数据收集
 *
 * 注意：如果cpu核心数只有1核，那么下面的线程池配置可能会出问题。
 * 比如网监数据收集，一个线程会一直执行，预估24小时完成。商户回调中，创建企业印章使用的同一个线程池，当回调任务进来时，先判断核心数是否已满，满了；判断队列是否已满，未满，存放在队列中了。
 * 第2、3  10个回调任务进来时，核心线程都被占用着执行数据收集，创建印章的任务都会存放在队列中。只要没有第11个回调任务进来，那么队里中的10个任务都会被阻塞，
 * 直到核销线程执行完数据收集任务后才会执行。严重影响了业务。（当第11个任务进来时，判断队列已满，会创建工作线程去执行第11个任务和队列中的任务，工作线程空闲后又会被销毁。最后又累计，又创建线程消费队列任务，反复影响业务）
 *
 * @author K
 * @date 2022/1/19 18:52
 */
@Slf4j
public class QueueBlock {

    @SneakyThrows
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1,
                3,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),
                new ThreadFactoryBuilder().setNameFormat("supervision-pool-%d").build());

        executor.execute(() -> {
            log.info("{} 网监数据初始化", Thread.currentThread().getName());
            try {
                Thread.sleep(1000 * 300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        for (int i = 0; i < 20; i++) {
            Thread.sleep(500);
            int finalI = i;
            executor.execute(() -> log.info("{} 创建印章{}", Thread.currentThread().getName(), finalI));
        }

    }


}
